/*******************************************************************************
 * Package: com.song.boot.springstudy.future01
 * Type:    CompletableFutureMain
 * Date:    2025-09-09 16:06
 *
 * Copyright (c) 2025 LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.boot.springstudy.thread.future01;

import lombok.SneakyThrows;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 功能描述：CompletableFuture使用
 *
 * @author Songxianyang
 * @date 2025-09-09 16:06
 */
public class CompletableFutureMain {
    @SneakyThrows
    public static void main(String[] args) {
        // 模拟线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        // 异步任务
            // 无返回值
        CompletableFuture.runAsync(()->{
            System.out.println("无返回值");
        },threadPool);
        // 有返回值
        CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> "有返回值", threadPool);

        System.out.println(supplyAsync.get());

        //异步任务回调 : 上一个CompletableFuture 的Completion 结果传入下一个 CompletableFuture
        CompletableFuture<String> thenApply = CompletableFuture
                // 异步任务：有返回值
                .supplyAsync(() ->
                        "有返回值",
                        threadPool)
                //任务完成后转换结果
                .thenApply(value ->
                        value + "--->异步任务回调"
                )
                .thenApply(value -> value + "--->2");
        System.out.println(thenApply.get());
        // 消费任务结果，无返回值
        CompletableFuture
                .supplyAsync(() -> "有返回值", threadPool)
                .thenAccept(s -> System.out.println(s+"--->消费任务结果，无返回值"))// 消费
                .thenAccept(s -> System.out.println(s+"--->2"));// 没有可消费的返回null
        // thenRun() - 任务完成后执行操作，不关心结果
        CompletableFuture<Void> thenRun = CompletableFuture
                .supplyAsync(() -> "---有返回值", threadPool)
                .thenRun(() -> {
                    System.out.println("无法接收到上一个CompletableFuture返回的结果");
                });
        System.out.println(thenRun.get());
        //exceptionally() - 异常处理
        CompletableFuture<String> exceptionally = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println("业务方法：：：：：");
                    if (true) throw new RuntimeException("模拟异常！！！！！！！！！");
                    return "会发生异常";
                }, threadPool)
                .exceptionally(ex -> ex.getMessage());
        System.out.println(exceptionally.get());
        // handle() - 无论成功或失败都处理
        CompletableFuture<String> handle = CompletableFuture
                .supplyAsync(() -> "---有返回值", threadPool)
                .handle((value, ex) -> ex != null ? "系统发生异常" : value+"--支持修改");
        System.out.println(handle.get());
        CompletableFuture<String> handleEx = CompletableFuture
                .supplyAsync(() -> {
                    System.out.println("业务方法：：：：：");
                    if (true) throw new RuntimeException("模拟异常！！！！！！！！！");
                    return "会发生异常";
                }, threadPool).handle((value, ex) -> ex != null ? "系统发生异常" : value);
        System.out.println(handleEx.get());

        CompletableFuture
                .supplyAsync(() -> "---有返回值", threadPool)
                .whenComplete((value, ex) -> {
                    if (ex != null) {
                        System.out.println("处理异常：" + ex.getMessage());
                    }
                    System.out.println("whenComplete::::::"+value);
                });
        System.out.println(handle.get());


        // 多任务组合
        // thenCompose() - 组合两个有依赖关系的任务
        CompletableFuture<String> supplyAsync1 = CompletableFuture.supplyAsync(() -> "---->有返回值1", threadPool);
        CompletableFuture<String> thenCompose = supplyAsync1.thenCompose(s -> CompletableFuture.supplyAsync(() -> "有返回值2"+s, threadPool));
        System.out.println(thenCompose.get());


        // thenCombine() - 合并两个独立任务的结果  智能合并两个
        CompletableFuture<String> supplyAsyncThenCombine1 = CompletableFuture.supplyAsync(() -> "---->有返回值1", threadPool);
        CompletableFuture<String> supplyAsyncThenCombine2 = CompletableFuture.supplyAsync(() -> "---->有返回值2", threadPool);
        CompletableFuture<String> supplyAsyncThenCombine3 = CompletableFuture.supplyAsync(() -> "---->有返回值1", threadPool);

        CompletableFuture<String> thenCombine = supplyAsyncThenCombine1.thenCombine(supplyAsyncThenCombine2, (s1, s2) -> s1 + " " + s2);
        System.out.println(thenCombine.get());


        //allOf() - 等待所有任务完成
        CompletableFuture<String> supplyAsyncAllOf1 = CompletableFuture.supplyAsync(() -> "---->有返回值1", threadPool);
        CompletableFuture<String> supplyAsyncAllOf2 = CompletableFuture.supplyAsync(() -> "---->有返回值2", threadPool);
        CompletableFuture<String> supplyAsyncAllOf3 = CompletableFuture.supplyAsync(() -> "---->有返回值3", threadPool);
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(supplyAsyncAllOf1, supplyAsyncAllOf2, supplyAsyncAllOf3);
        voidCompletableFuture.join();
        voidCompletableFuture.thenRun(() -> System.out.println("任务全部执行完"));
        // 另一种写法：allOf() - 等待所有任务完成

        /*
        模拟：数据分批 一共1000条数据  分为5批 也就是说5个CompletableFuture
        List<CompletableFuture> cfs = new ArrayList<>();
        for{
        cfs.add();
        }
        //获取多个任务
        CompletableFuture[] futureArray = cfs.toArray(new CompletableFuture[0]);
        //所有任务全部等待执行完
        CompletableFuture.allOf(futureArray).join();
         */

        // anyOf() - 等待任意一个任务完成
        CompletableFuture<Object> any = CompletableFuture.anyOf(supplyAsyncAllOf1, supplyAsyncAllOf2, supplyAsyncAllOf3);
        any.thenAccept(result -> System.out.println("最先完成的任务: " + result));



        threadPool.shutdown();

    }
}
